/**
 *	The NeuroCoSA Toolkit
 *	Copyright (C) 2003-6 Stuart Meikle.
 *
 *	This is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU Lesser General Public
 *	License as published by the Free Software Foundation; either
 *	version 2.1 of the License, or (at your option) any later version.
 *
 *	This library is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *	Lesser General Public License for more details.
 *
 * @author	Stuart Meikle
 * @version	2006-halloween(mk2)
 * @license	LGPL
 */
package org.stumeikle.NeuroCoSA.AutoCluster;

/**
 * Hash_bin .h in java form.
 * A memory , similar to STLTMemory but based on autocluster
 *
 * stumeikle 20060408
 *
 */
 
import java.util.*;


public	class	AutoClusterMemory
{
    private	NMeasurable		iCentroid;
    private	long			iNumEntries;
    private	LinkedList<NMeasurable>	iEntry;
    private	double			iSize;
    private	long			iId;
    private	boolean			iIgnore;
    private	long			iCreationTime;
    private	long			iNeedsToSplitCount;
    private	double			iCentroidChange;
    private	double			iNumCentroidChanges;
    private	double			iSizeChange;
    private	double			iNumSizeChanges;
    private	double			iLastSize;
    private	double			iWeight;
    private	boolean			iSolid;
    private	double			iDistanceValue; ///distance from memory centroid to last learn input
    private	long			iDistanceTime; /// when was the distance stored ?
    private	double			iTestDistanceValue;///distance from mem centroid to last given test value
    private	long			iTestTime; /// when was the test distance stored ?
    private	Object			iOpaque;
    public	static final double	UNDEFINED_DISTANCE = 1.0;
    
    public	double			getSize()
    { return iSize; }
    
    public	long			getID()
    { return iId; }
    
    public	void			setSize( double d )
    { iSize = d; }
    
    public	void			setIgnore( boolean b )
    { iIgnore = b; }
    
    public	boolean			getIgnore()
    { return iIgnore; }
    
    public	NMeasurable		getCentroid()
    { return iCentroid; }

    public	long			getNumEntries()
    { return iNumEntries; }
    
    public	long			getCreateTime()
    { return iCreationTime; }
    
    public	LinkedList		getEntryList()
    { return iEntry; }
    
    public	AutoClusterMemory(NMeasurable c, double s, long ct, long id)
    {
    	//constructor
    	
    	//initialise the vars
    	iNumEntries = 0 ;
    	iNeedsToSplitCount=0;
    	iCentroidChange =0.0;
    	iNumCentroidChanges=0.0;
    	iSizeChange=0.0;
    	iNumSizeChanges=0.0;
    	iLastSize=0.0;
    	iWeight = 0.0;
    	iSolid = false;
    	iEntry = new LinkedList<NMeasurable>();
	    
	//set a value for the centroid
        iCentroid=c;
	    
        //set a size for the bin
        iSize=s;
        iIgnore =false;
    
        iId = id; // some static var.... FIX ME
        iCreationTime = ct; // FIX M
        iDistanceValue = UNDEFINED_DISTANCE;
	iTestDistanceValue = UNDEFINED_DISTANCE;
        iOpaque = null;
	iTestTime = 0;
	iDistanceTime = 0;
    }
    
    public	void			storeDistance( double d, long t )
    {
       	iDistanceValue = d;
        iDistanceTime  = t;
    }
    
    public	double			getDistanceFromLearnValue()
    {
        return iDistanceValue;
    }
    public	long			getLearnTime()
    {
	return iDistanceTime;
    }

    public	void			storeTestDistance( double d , long t)
    {
  	iTestDistanceValue = d;
	iTestTime = t;
    }

    public	double			getTestDistance()
    {
	return iTestDistanceValue;
    }
    public	long			getTestTime()
    {
	return iTestTime; 
    }
    
    public	void			setOpaque( Object o )
    { iOpaque = o; }
    
    public	Object			getOpaque()
    { return iOpaque; }
    
    
    public	void			addEntry( NMeasurable t )
    {
        //add the entry
        if ( iSolid ==false)
        {
            iEntry.add(t); 
        }
    
        iNumEntries ++;
    
        //recalculate the centroid
        NMeasurable	c = iCentroid.createCopy();
        NMeasurable	orig_cent = iCentroid;
	double		deltac, deltas;
	
	//centroid->newSetAsCentroid( t, c, weight );
	//set our values so that we're the centroid of the list of points
	c.multiplyByScalar(iWeight);
	c.add( t );
	iWeight= iWeight + 1.0;
	c.divideByScalar( iWeight );
	iCentroid = c;
    
        deltac=  orig_cent.distanceTo(iCentroid);
    	iNumCentroidChanges += 1.0;
        iCentroidChange += deltac;
        deltas= Math.abs(iSize - iLastSize);
        iNumSizeChanges += 1.0;
        iSizeChange += deltas;
        iLastSize = iSize;
    }
    
    double	getSizeChangeRatio()
    {
        if (iNumSizeChanges > 0.0)
        {
      	    return iSizeChange / iNumSizeChanges;
        }else
    	    return 10.0;
    }
    
    double	getCentroidChangeRatio()
    {
        if (iNumCentroidChanges > 0.0)
        {
      	    return iCentroidChange / iNumCentroidChanges;
        }else
    	    return 10.0;
    }
    
    long	getNeedsToSplitCount()
    {
    	return iNeedsToSplitCount;
    }
    
    void	incrNeedsToSplitCount()
    {
    	iNeedsToSplitCount ++;
    }
    
    void	consolidate()
    {
        //leave the weight as it is but remove the entries.
        if (iSolid ==true)	return;
        //c++: entry.clear();
        iEntry.clear();
        iSolid = true;
    }
    
    boolean	isConsolidated()
    {
    	return iSolid;
    }
    
    void	removeFirstEntry()
    {
        iNumEntries--;
	iEntry.remove(0);
    }
}

